package com.wxy.favorites.websocket;

import cn.hutool.core.util.StrUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.concurrent.ConcurrentHashMap;

/**
 * websocket的处理类。
 * 作用相当于HTTP请求
 * 中的controller
 */
@Component
@Slf4j
@ServerEndpoint("/websocket/{sid}")
public class WebSocketServer {

    /**
     * 静态变量，用来记录当前在线连接数。应该把它设计成线程安全的。
     */
    private static int onlineCount = 0;
    /**
     * concurrent包的线程安全Set，用来存放每个客户端对应的WebSocket对象。
     */
    private static final ConcurrentHashMap<String, WebSocketServer> webSocketMap = new ConcurrentHashMap<>();
    /**
     * 与某个客户端的连接会话，需要通过它来给客户端发送数据
     */
    private Session session;
    /**
     * 接收sid
     */
    private String sid;

    /**
     * 连接建立成
     * 功调用的方法
     */
    @OnOpen
    public void onOpen(Session session, @PathParam("sid") String sid) {
        this.session = session;
        this.sid = sid;
        webSocketMap.put(sid, this);
        addOnlineCount();
        log.info("用户连接成功：sid = {}, online = {}", sid, getOnlineCount());
    }

    /**
     * 连接关闭
     * 调用的方法
     */
    @OnClose
    public void onClose() {
        webSocketMap.remove(sid);
        subOnlineCount();
        log.info("用户退出：sid = {}, online = {}", sid, getOnlineCount());
    }

    /**
     * 收到客户端消
     * 息后调用的方法
     *
     * @param message 客户端发送过来的消息
     **/
    @OnMessage
    public void onMessage(String message, Session session) {
        log.info("收到用户消息：sid = {}, message = {}", sid, message);
    }


    /**
     * @param session
     * @param error
     */
    @OnError
    public void onError(Session session, Throwable error) {
        log.error("通信错误：sid = {}", sid, error);
    }

    /**
     * 实现服务
     * 器主动推送
     */
    public void sendMessage(String message) {
        try {
            this.session.getBasicRemote().sendText(message);
        } catch (IOException e) {
            log.error("发送消息失败：sid = {}, message = {}", sid, message, e);
        }
    }

    /**
     * 发送自定
     * 义消息
     **/
    public static void sendInfo(String message, String sid) {
        log.info("发送消息：sid = {}, message = {}", sid, message);
        if (StrUtil.isNotBlank(sid) && webSocketMap.containsKey(sid)) {
            webSocketMap.get(sid).sendMessage(message);
        } else {
            log.error("用户离线：sid = {}", sid);
        }
    }

    /**
     * 获取当前连接
     *
     * @param sid
     * @return
     */
    public static WebSocketServer findChannel(String sid) {
        return webSocketMap.get(sid);
    }

    /**
     * 向所有客户端发送消息
     *
     * @param message
     */
    public static void sendAll(String message) {
        webSocketMap.values().forEach(s -> s.sendMessage(message));
    }


    /**
     * 获得此时的
     * 在线人数
     *
     * @return
     */
    public static synchronized int getOnlineCount() {
        return onlineCount;
    }

    /**
     * 在线人
     * 数加1
     */
    public static synchronized void addOnlineCount() {
        WebSocketServer.onlineCount++;
    }

    /**
     * 在线人
     * 数减1
     */
    public static synchronized void subOnlineCount() {
        WebSocketServer.onlineCount--;
    }

}

